package com.hooper.hosp.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.hooper.cmn.client.DictClient;
import com.hooper.common.util.MD5;
import com.hooper.common.util.helper.HttpRequestHelper;
import com.hooper.hosp.model.hosp.Hospital;
import com.hooper.hosp.repository.HospRepository;
import com.hooper.hosp.service.HospService;
import com.hooper.hosp.service.HospitalSetService;
import com.hooper.hosp.utils.MongoPageUtils;
import com.hooper.hosp.vo.hosp.HospitalQueryVo;
import com.hooper.hospital.common.exception.HospitalException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.hooper.hospital.common.constant.DictConstant.DICT_CODE_HOSP;
import static com.hooper.hospital.common.constant.DictConstant.FULL_ADDRESS;
import static com.hooper.hospital.common.constant.HospConstant.*;
import static com.hooper.hospital.common.result.ResultCodeEnum.*;

/**
 * @author Tim Hooper
 * @version 1.0
 * @time 2022/09/28/10:31
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class HospServiceImpl implements HospService {

    private final HospRepository hospRepository;
    private final HospitalSetService hospitalSetService;
    private final DictClient dictClient;

    @Override
    public boolean saveOrUpdate(Map<String, Object> map) {
        String mapString = JSONObject.toJSONString(map);
        log.info("Map===>:{}", mapString);
        Hospital hospital = JSONObject.parseObject(mapString, Hospital.class);
        if (hospital == null) {
            throw new HospitalException(OBJECT_IS_NULL);
        }
        String hoscode = hospital.getHoscode();
        Hospital dbHosp = hospRepository.findHospitalByHoscode(hoscode);

        if (dbHosp == null) {
            hospital.setStatus(DEFAULT_STATUS);
            hospital.setCreateTime(TIME_NOW);
        } else {
            hospital.setStatus(dbHosp.getStatus());
            hospital.setCreateTime(dbHosp.getCreateTime());
        }
        hospital.setUpdateTime(TIME_NOW);
        hospital.setIsDeleted(NOT_DELETED);
        hospRepository.save(hospital);

        return true;
    }

    @Override
    public Map<String, Object> signKeyCheckAndMapSwitch(HttpServletRequest request) {
        Map<String, String[]> requestMap = request.getParameterMap();
        Map<String, Object> map = HttpRequestHelper.switchMap(requestMap);
        String hoscode = (String) map.get("hoscode");
        String signKey = hospitalSetService.getSignKeyByHoscode(hoscode);
        signKey = MD5.encrypt(signKey);
        log.info("hosp signKey:{}\t hospSet signkey{}", map.get("sign"), signKey);
        if (!signKey.equals(map.get("sign"))) {
            throw new HospitalException(SIGN_ERROR);
        }
        return map;
    }

    @Override
    public Hospital getHospitalByHoscode(String hoscode) {
        return hospRepository.findHospitalByHoscode(hoscode);
    }

    @Override
    public Page<Hospital> pageByConditions(Integer currentPage, Integer pagesSize, HospitalQueryVo hospQueryVo) {
        Pageable pageable = MongoPageUtils.getPageable(currentPage, pagesSize);

        //set the conditions
        Hospital hospital = new Hospital();
        BeanUtils.copyProperties(hospQueryVo, hospital);
        hospital.setIsDeleted(NOT_DELETED);
        Example<Hospital> example = MongoPageUtils.getExample(hospital);
        //retrieve
        return hospRepository.findAll(example, pageable);
    }

    @Override
    public void changeStatus(String id, String status) {
        //check if the params are empty
        if (StringUtils.isAnyBlank(id, status)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        //make sure the status is validated
        if (!Character.isDigit(status.charAt(0))) {
            throw new HospitalException(PARAM_TYPE_ERROR);
        }
        if (!(STATUES_ACTIVATE.equals(status) || STATUES_NOT_ACTIVATE.equals(status))) {
            throw new HospitalException(NO_SUCH_STATUES);
        }

        //make sure the db contains this data
        Hospital hospital = hospRepository.findHospitalById(id);
        if (hospital == null) {
            throw new HospitalException(NO_SUCH_DATA);
        }
        //change status and update time
        hospital.setStatus(Integer.parseInt(status));
        hospital.setUpdateTime(TIME_NOW);
        hospRepository.save(hospital);
    }

    @Override
    public Hospital getHospDetailById(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        //check if this data exists in the db
        boolean present = hospRepository.findById(id).isPresent();
        if (!present) {
            throw new HospitalException(NO_SUCH_DATA);
        }

        //retrieve the hosp
        Hospital hospital = hospRepository.findById(id).get();
        //and fill the missing field
        return this.completeHosp(hospital);
    }

    @Override
    public Hospital completeHosp(Hospital hospital) {
        String hospLevel = dictClient.getDictName(DICT_CODE_HOSP, hospital.getHostype());
        Map<String, Object> param = hospital.getParam();
        param.put(DICT_CODE_HOSP, hospLevel);
        //retrieve the specific address including Province, City, District,County
        String province = dictClient.getLocation(hospital.getProvinceCode());
        String city = dictClient.getLocation(hospital.getCityCode());
        String district = dictClient.getLocation(hospital.getDistrictCode());
        param.put(FULL_ADDRESS, province + city + district);
        hospital.setParam(param);
        return hospital;
    }

    @Override
    public List<Hospital> findLikeName(String hosname) {
        if (StringUtils.isEmpty(hosname)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        //fuzzy query
        List<Hospital> hospitalList = hospRepository.findAllByHosnameLike(hosname);
        if (hospitalList == null) {
            return new ArrayList<>();
        }
        return hospitalList;
    }

    @Override
    public Map<String, Object> getHospInfo(String hoscode) {
        if (StringUtils.isEmpty(hoscode)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        Map<String, Object> result = new HashMap<>(2);
        Hospital hospital = this.completeHosp(this.getHospitalByHoscode(hoscode));
        result.put("hospital", hospital);
        result.put("bookingRules", hospital.getBookingRule());
        hospital.setBookingRule(null);
        return result;
    }
}
